package cn.sh.yhk.acl.filter;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.sh.yhk.acl.UserDetailsInfo;
import cn.sh.yhk.acl.cache.UserTokenCacheInfo;
import cn.sh.yhk.acl.cache.UserTokenCacheService;
import cn.sh.yhk.acl.jwt.JwtTokenUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import static cn.sh.yhk.acl.jwt.JwtTokenUtil.TOKEN_HEADER;

/**
 * @Classname Yhk
 * @Description TODO
 * @Version 1.0.0
 * @Date 2024/10/2 17:02
 * @Created by y6522
 */
@Component
@Slf4j
public class JWTAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private UserTokenCacheService userTokenCacheService;

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.info("请求地址{}", request.getRequestURI());
        if (notNeedFilter(request)) {
            filterChain.doFilter(request, response);
        }
        String token = request.getHeader(TOKEN_HEADER);
        if (StringUtils.hasText(token)) {
            log.info("token:{}", token);
            if (!JwtTokenUtil.verifyToken(token)) {
                ResponseProcessing(request, response, "error-token", null);
            }
            UserTokenCacheInfo tokenCache = userTokenCacheService.
                    getUserTokenCacheByUserName(JwtTokenUtil.getUserNameFromToken(token));
            if (ObjectUtils.isEmpty(tokenCache.getToken())) {
                ResponseProcessing(request, response, "no-login", null);
                return;
            }
            if (tokenCache.getToken().equals(token)) {
                if (ObjectUtils.isEmpty(tokenCache) && tokenCache.getMaxExpirationDate().before(new Date())) {
                    ResponseProcessing(request, response, "no-login", null);
                    return;
                }
                if (tokenCache.getExpirationDate().before(new Date()) && tokenCache.getMaxExpirationDate().after(new Date())) {
                    ResponseProcessing(request, response, "renovate-token", null);
                    return;
                }
                //用户是否授权
                if (SecurityContextHolder.getContext().getAuthentication() == null) {
                    //将User 封装到 securityContextHolder。 封装到securityContextHolder以后，其他过滤器就不会在拦截
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tokenCache, null, null);
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
                //认证成功，更改缓存里面的调用接口时间，主要用于判断是否活跃
                userTokenCacheService.userTokenCacheOldOperationDateUpdate(tokenCache, JwtTokenUtil.getUserNameFromToken(token));
            } else {
                ResponseProcessing(request, response, "error-token", null);
                return;
            }
            filterChain.doFilter(request, response);
        }


        //需要认证token的接口才进入
//        if (!notNeedFilter(request)) {
//            // 获取 token
//            if (StringUtils.hasText(token)) {
//                // 解析token，获取 username
//                String username = jwtTokenUtil.getUserNameFromToken(token);
//                //判断是否有该username 的缓存,（登录存入缓存，注销清除缓存）
//                UserTokenCacheInfo userTokenCacheInfo = userTokenCacheService.getUserTokenCacheById(username);
//                if (userTokenCacheInfo != null) {
//                    //判断存储的token跟传入的token是否一致,
//                    String CToken = userTokenCacheInfo.getToken();
//                    if (CToken.equals(token)) {
//                        //判断token是否过期
//                        if (jwtTokenUtil.isTokenExpired(token)) {
//                            //判断是否超过最大失效时间
//                            if (userTokenCacheInfo.getMaxExpirationDate().before(new Date())) {
//                                ResponseProcessing(request, response, "exceeding-maximum-failure-time", null);
//                            }
//
//                            //是否超过设定时间没有操作
//                            else if (DateUtil.offsetMinute(userTokenCacheInfo.getOldOperationDate(), userTokenCacheInfo.getInactiveMinute()).before(new Date())) {
//                                ResponseProcessing(request, response, "exceeding-inactive-time", null);
//                            }
//                            //满足条件 活跃用户，又没有超过最大失效时间，从新生成token给客户端
//                            else {
//                                UserDetailsInfo userDetailsInfo = new UserDetailsInfo();
//                                userDetailsInfo.setUsername(username);
//                                //生成jwt
//                                String newToken = jwtTokenUtil.generateToken(userDetailsInfo);
//                                //更新缓存
//                                userTokenCacheService.userTokenCacheUpdate(newToken, username);
//                                ResponseProcessing(request, response, "renovate-token", newToken);
//                            }
//                        } else {
//                            //用户是否授权
//                            if (SecurityContextHolder.getContext().getAuthentication() == null) {
//                                //将User 封装到 securityContextHolder。 封装到securityContextHolder以后，其他过滤器就不会在拦截
//                                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userTokenCacheInfo, null, null);
//                                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//                            }
//                            //认证成功，更改缓存里面的调用接口时间，主要用于判断是否活跃
//                            userTokenCacheService.userTokenCacheOldOperationDateUpdate(userTokenCacheInfo, username);
//                        }
//                    }
//                }
//
//            }
//            filterChain.doFilter(request, response);
//        }

    }

    //直接返回给客户端
    private void ResponseProcessing(HttpServletRequest request, HttpServletResponse response, String type, String token) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("uri", request.getRequestURI());
        if (type.equals("exceeding-maximum-failure-time")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

            map.put("message", "exceeding-maximum-failure-time");
        } else if (type.equals("exceeding-inactive-time")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            map.put("message", "exceeding-inactive-time");
        } else if (type.equals("renovate-token")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            map.put("message", "renovate-token");
            map.put("token", token);
        } else if (type.equals("no-login")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            map.put("message", "未登录");
        } else if (type.equals("error-token")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            map.put("message", "认证已失效");
        } else {

            map.put("message", "身份认证失败");
        }
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String resBody = JSONUtil.toJsonStr(map);
        PrintWriter printWriter = response.getWriter();
        printWriter.print(resBody);
        printWriter.flush();
        printWriter.close();
    }


    private static final Pattern PATH_PATTERN = Pattern.compile("^/webSocket+/.+$");
    /**
     * 判断是否可以通过过滤
     */
    private boolean notNeedFilter(HttpServletRequest request) {
        //登录接口
        String url =request.getRequestURI();
        return (request.getContextPath() + "/login").equals(url)
                ||PATH_PATTERN.matcher(url).matches();
    }

    public static void main(String[] args) {
        System.out.println(PATH_PATTERN.matcher("/WebSocket/asdas/5644").matches());
    }

}


